package com.xinqi.modules.course.clazz.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xinqi.common.base.data.ListDataDTO;
import com.xinqi.common.base.enums.YesNoEnum;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.response.PageInfo;
import com.xinqi.common.base.response.Param;
import com.xinqi.common.base.response.R;
import com.xinqi.common.base.utils.spring.Spring;
import com.xinqi.common.core.constant.CacheConstants;
import com.xinqi.common.core.constant.ChatRemindConstants;
import com.xinqi.common.core.enums.ChatRemindTypeEnum;
import com.xinqi.common.core.enums.RegisterRoleEnum;
import com.xinqi.common.core.utils.MessageUtils;
import com.xinqi.common.mybatis.data.service.impl.BaseServiceImpl;
import com.xinqi.common.mybatis.utils.Pages;
import com.xinqi.common.mybatis.utils.Queries;
import com.xinqi.common.redis.utils.RedisUtils;
import com.xinqi.common.satoken.utils.LoginHelper;
import com.xinqi.modules.chat.chat.group.client.RemoteChatClient;
import com.xinqi.modules.chat.chat.official.client.ChatRemindContentClient;
import com.xinqi.modules.chat.chat.official.dto.req.ChatRemindContentCreateDTO;
import com.xinqi.modules.course.clazz.convert.ClassJoinAuditConvert;
import com.xinqi.modules.course.clazz.domain.ClassJoinAuditEntity;
import com.xinqi.modules.course.clazz.domain.ClassStudentEntity;
import com.xinqi.modules.course.clazz.dto.req.*;
import com.xinqi.modules.course.clazz.dto.rsp.ClassJoinAuditResultDTO;
import com.xinqi.modules.course.clazz.dto.rsp.ClassResultDTO;
import com.xinqi.modules.course.clazz.dto.rsp.ClassStudentResultDTO;
import com.xinqi.modules.course.clazz.mapper.ClassJoinAuditMapper;
import com.xinqi.modules.course.clazz.service.*;
import com.xinqi.modules.course.course.enums.ClassAuditEnum;
import com.xinqi.modules.course.course.enums.ClassAuditJsonParamEnum;
import com.xinqi.modules.course.course.enums.ClassStudentRelationshipEnum;
import com.xinqi.modules.course.course.enums.clazz.ClassAuditStatusEnum;
import com.xinqi.modules.course.course.enums.clazz.ClassOperationLogTypeEnum;
import com.xinqi.modules.course.demonstrate.service.DemonstrateService;
import com.xinqi.modules.user.user.client.UserClient;
import com.xinqi.modules.user.user.dto.req.UserImitateDTO;
import com.xinqi.modules.user.user.dto.req.UserRegisterDTO;
import com.xinqi.modules.user.user.dto.rsp.UserResultDTO;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 学生加入班级审核服务层实现
 *
 * @author: system
 * @date: 2023/01/17
 */
@Service("classJoinAuditService")
@RequiredArgsConstructor
public class ClassJoinAuditServiceImpl extends BaseServiceImpl<ClassJoinAuditMapper, ClassJoinAuditEntity> implements ClassJoinAuditService {
    private final ClassJoinAuditMapper classJoinAuditMapper;
    private final ClassJoinAuditConvert classJoinAuditConvert;
    private final ClassService classService;
    @Lazy
    private final ClassStudentService classStudentService;
    @Lazy
    private final ClassOperationLogService classOperationLogService;
    private final ClassMqService classMqService;
    @Lazy
    private final ChatRemindSyncService chatRemindSyncService;
    private final ChatRemindContentClient remindContentClient;
    @Lazy
    private final DemonstrateService demonstrateService;
    private final UserClient userClient;
    private final RemoteChatClient remoteChatClient;

    /**
     * 分页查询 学生加入班级审核数据
     */
    @Override
    @DS("slaver")
    public PageInfo<ClassJoinAuditResultDTO> page(Param pageable, ClassJoinAuditQueryDTO query) {
        IPage<ClassJoinAuditResultDTO> pageList = classJoinAuditMapper.pageList(Pages.page(pageable), query);
        this.setRelationAttribute(pageList.getRecords());
        return Pages.convert(pageList);
    }

    private void setRelationAttribute(List<ClassJoinAuditResultDTO> list) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        for (ClassJoinAuditResultDTO auditResult : list) {
            if (StringUtils.isNotEmpty(auditResult.getAuditContent())) {
                Map<String, String> relationMap = classJoinAuditConvert.paraMap(auditResult.getAuditContent());
                auditResult.setStudentName(relationMap.get(ClassAuditJsonParamEnum.学生真实姓名.getCode()));
                auditResult.setRelationship(relationMap.get(ClassAuditJsonParamEnum.与学生的关系.getCode()));
            }
        }
    }

    /**
     * 查询 app端没有分页
     */
    @Override
    public List<ClassJoinAuditResultDTO> findList(ClassJoinAuditQueryDTO query) {
        return classJoinAuditMapper.findList(query);
    }

    /**
     * 查询 学生加入班级审核数据
     */
    @Override
    public List<ClassJoinAuditResultDTO> find(ClassJoinAuditQueryDTO query) {
        return list(wrapper(query)).stream().map(classJoinAuditConvert::convert).collect(Collectors.toList());
    }

    private LambdaQueryWrapper<ClassJoinAuditEntity> wrapper(ClassJoinAuditQueryDTO query) {
        LambdaQueryWrapper<ClassJoinAuditEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(ClassJoinAuditEntity::getId, v));
        Queries.accept(query.getClassId(), v -> wrapper.eq(ClassJoinAuditEntity::getClassId, v));
        Queries.accept(query.getStudentId(), v -> wrapper.eq(ClassJoinAuditEntity::getStudentId, v));
        Queries.accept(query.getStatus(), v -> wrapper.eq(ClassJoinAuditEntity::getStatus, v));
        return wrapper;
    }

    /**
     * 根据id查询 学生加入班级审核数据
     */
    @Override
    public ClassJoinAuditResultDTO findById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return Optional.ofNullable(classJoinAuditMapper.selectById(id)).map(classJoinAuditConvert::convert).orElse(null);
    }

    /**
     * 新增 学生加入班级审核数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long insert(ClassJoinAuditCreateDTO dto) {
        ClassJoinAuditEntity entity = classJoinAuditConvert.create(dto);
        this.save(entity);
        return entity.getId();
    }

    /**
     * 根据id修改 学生加入班级审核数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateById(ClassJoinAuditUpdateDTO dto) {
        ClassJoinAuditEntity entity = classJoinAuditConvert.update(dto);
        return updateById(entity);
    }

    /**
     * 根据id删除 学生加入班级审核数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return removeById(id);
    }

    /**
     * 根据id删除 学生加入班级审核数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(ClassJoinAuditDeleteDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getId()), "ID不能为空");
        return deleteById(dto.getId());
    }

    @Override
    public ClassJoinAuditResultDTO detail(Long id) {
        return classJoinAuditMapper.detail(id);
    }

    /**
     * 老师审核班级加课申请
     *
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean accept(Long auditId) {
        ClassJoinAuditEntity old = Optional.ofNullable(getById(auditId)).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("审核数据不存在"));
        ClassResultDTO classResultDTO = Optional.ofNullable(classService.findById(old.getClassId())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("班级数据不存在"));

        //解析审核数据
        ClassAuditJsonParamDTO auditJson = classJoinAuditConvert.convertToParam(old.getAuditContent());

        //班级学生姓名判重
        ClassStudentResultDTO masterExist = classStudentService.findByClassIdAndStudentName(classResultDTO.getId(), auditJson.getStudentName());
        boolean check = Objects.isNull(masterExist) || Objects.equals(auditJson.getStudentName(), masterExist.getStudentName()) && Objects.equals(auditJson.getMobile(), masterExist.getMobile());
        CommonErrors.BAD_REQUEST.check(check, "学生姓名在班级中已存在");

        //判断虚拟学生是否有账号
        UserResultDTO userResultDTO = this.checkImitateUserAccount(auditJson.getMobile(), auditJson.getStudentName());

        //判断关系用户是否已加班
        Boolean isInClass = this.checkUserIsInClass(classResultDTO.getId(), old.getStudentId());
        if (Objects.nonNull(userResultDTO)) {
            if (isInClass) {
                throw CommonErrors.BAD_REQUEST.asException("已加入班级，如需绑定其他学生请更换手机号");
            } else {
                Boolean exist = this.checkUserIsInClass(classResultDTO.getId(), userResultDTO.getId());
                if (exist) {
                    this.acceptRelation(old, classResultDTO, old.getStudentId(), userResultDTO.getId(), auditJson);
                } else {
                    this.acceptBoth(old, classResultDTO, old.getStudentId(), userResultDTO.getId(), auditJson);
                }
            }
        } else {
            if (isInClass) {
                throw CommonErrors.BAD_REQUEST.asException("已加入班级，如需绑定其他学生请更换手机号");
            } else {
                //创建用户
                userResultDTO = this.imitateUser(auditJson.getMobile(), auditJson.getStudentName());
                this.acceptBoth(old, classResultDTO, old.getStudentId(), userResultDTO.getId(), auditJson);
            }
        }

        return true;
    }

    /**
     * 审核通过、虚拟学生和关系学生都加入班级
     *
     * @param old            ClassJoinAuditEntity
     * @param classResultDTO ClassResultDTO
     * @param relationId     关系用户学生id
     * @param studentId      虚拟学生用户id
     * @param auditJson      审核内容json
     */
    @Transactional(rollbackFor = Exception.class)
    public void acceptBoth(ClassJoinAuditEntity old, ClassResultDTO classResultDTO, Long relationId, Long studentId, ClassAuditJsonParamDTO auditJson) {
        //将关系用户加入到班级中
        this.autoAuditRelationalIntoClass(classResultDTO.getCourseId(), classResultDTO.getId(), relationId, old.getAuditContent(), YesNoEnum.YES.ordinal(), studentId, auditJson);
        //将虚拟用户加入到班级中
        auditJson.setRelationship(ClassStudentRelationshipEnum.虚拟主学生.getDescribe());
        classStudentService.insertStudent(LoginHelper.getUserId(), studentId, classResultDTO.getCourseId(), classResultDTO.getId(), YesNoEnum.NO.ordinal(), 0L, auditJson);

        Spring.committed(() -> {
            //虚拟用户加课后处理
            classMqService.studentJoinClass(old.getClassId(), studentId);
            //关系用户加入班级群
            remoteChatClient.classJoinGroup(old.getClassId(), relationId);
            //关系用户发消息
            chatRemindSyncService.acceptPass(old.getClassId(), relationId, ChatRemindTypeEnum.AUDIT_PASS);
        });
    }


    /**
     * 审核通过、虚拟学生和关系学生都加入班级
     *
     * @param old            ClassJoinAuditEntity
     * @param classResultDTO ClassResultDTO
     * @param relationId     关系用户学生id
     * @param studentId      虚拟学生用户id
     * @param auditJson      审核内容json
     */
    @Transactional(rollbackFor = Exception.class)
    public void acceptRelation(ClassJoinAuditEntity old, ClassResultDTO classResultDTO, Long relationId, Long studentId, ClassAuditJsonParamDTO auditJson) {
        //将关系用户加入到班级中并绑定学生id
        this.autoAuditRelationalIntoClass(classResultDTO.getCourseId(), classResultDTO.getId(), relationId, old.getAuditContent(), YesNoEnum.YES.ordinal(), studentId, auditJson);
        //关系用户发消息
        Spring.committed(() -> {
            // 关系用户加入班级群
            remoteChatClient.classJoinGroup(old.getClassId(), relationId);
            // 发送审核通过信息
            chatRemindSyncService.acceptPass(old.getClassId(), relationId, ChatRemindTypeEnum.AUDIT_PASS);
        });
    }

    /**
     * 学生在登录的情况下，通过扫描二维码或输入验证码发起加课申请,这里需要注意：学生可能多次申请加课，应前端要求申请之后返回申请成功后的状态
     *
     * @param dto 加课dto
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassJoinAuditResultDTO apply(ClassJoinAuditCreateDTO dto) {
        ClassResultDTO classResult = Optional.ofNullable(classService.findByClassId(dto.getClassId())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException(MessageUtils.message("remind.content.class.not.blank")));
        Long auditId;
        //解析审核数据
        ClassAuditJsonParamDTO auditJson = classJoinAuditConvert.convertToParam(dto.getAuditContent());

        //班级学生姓名判重
        ClassStudentResultDTO masterExist = classStudentService.findByClassIdAndStudentName(dto.getClassId(), auditJson.getStudentName());
        boolean check = Objects.isNull(masterExist) || Objects.equals(auditJson.getStudentName(), masterExist.getStudentName()) && Objects.equals(auditJson.getMobile(), masterExist.getMobile());
        CommonErrors.BAD_REQUEST.check(check, "学生姓名在班级中已存在");

        // 获取加班用户ID
        Long studentId = Objects.nonNull(dto.getStudentId()) ? dto.getStudentId() : LoginHelper.getUserId();
        dto.setStudentId(studentId);

        //判断关系用户是否已加班
        Boolean isInClass = this.checkUserIsInClass(dto.getClassId(), studentId);

        //自动审核
        if (ClassAuditEnum.AUTO.getCode().equals(classResult.getAuditMethod())) {
            //判断虚拟学生是否有账号
            UserResultDTO userResultDTO = this.checkImitateUserAccount(auditJson.getMobile(), auditJson.getStudentName());



            if (Objects.nonNull(userResultDTO)) {
                if (isInClass) {
                    throw CommonErrors.BAD_REQUEST.asException("已加入班级，如需绑定其他学生请更换手机号");
                } else {
                    //判断虚拟用户是否在班级中
                    Boolean exist = this.checkUserIsInClass(dto.getClassId(), userResultDTO.getId());
                    if (exist) {
                        return this.autoAuditRelation(dto, auditJson, userResultDTO.getId());
                    } else {
                        return this.autoAuditBoth(dto, auditJson, userResultDTO.getId());
                    }
                }
            } else {
                if (isInClass) {
                    throw CommonErrors.BAD_REQUEST.asException("已加入班级，如需绑定其他学生请更换手机号");
                } else {
                    //创建用户
                    userResultDTO = this.imitateUser(auditJson.getMobile(), auditJson.getStudentName());
                    return this.autoAuditBoth(dto, auditJson, userResultDTO.getId());
                }
            }
            //手动审核
        } else {
            if (isInClass) {
                throw CommonErrors.BAD_REQUEST.asException("已加入班级，如需绑定其他学生请更换手机号");
            } else {
                auditId = this.applyAudit(dto, classResult);
            }
        }

        return classJoinAuditConvert.convert(getById(auditId));
    }


    /**
     * 申请加课-免审核和手动审核的逻辑
     *
     * @param dto       加课dto
     * @param auditJson 审核数据
     * @return ClassJoinAuditResultDTO 返回关系用户加班成功的信息
     */
    @Transactional(rollbackFor = Exception.class)
    public ClassJoinAuditResultDTO autoAuditRelation(ClassJoinAuditCreateDTO dto, ClassAuditJsonParamDTO auditJson, Long studentId) {
        ClassResultDTO classResult = Optional.ofNullable(classService.findByClassId(dto.getClassId())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException(MessageUtils.message("remind.content.class.not.blank")));
        Long auditId;
        auditId = this.autoAuditRelationalIntoClass(classResult.getCourseId(), classResult.getId(), dto.getStudentId(), dto.getAuditContent(), YesNoEnum.YES.ordinal(), studentId, auditJson);
        //免审核不需要给关系用户发消息，只需要给老师发消息
        Spring.committed(() -> {
            //关系用户加入班级群
            remoteChatClient.classJoinGroup(dto.getClassId(), studentId);
            // 加入班级发消息
            chatRemindSyncService.studentJoinClass(classResult.getId(), null, ChatRemindTypeEnum.AUTO_AUDIT);
        });
        return classJoinAuditConvert.convert(getById(auditId));
    }

    @Transactional(rollbackFor = Exception.class)
    public Long applyAudit(ClassJoinAuditCreateDTO dto, ClassResultDTO classResult) {
        //每次重新发起审核后，都需要先判断是否自动审核，只有手动审核的班级才进行审核查询
        ClassJoinAuditResultDTO auditResult = findByClassIdAndStudentId(dto.getClassId(), dto.getStudentId());
        CommonErrors.BAD_REQUEST.check(Objects.isNull(auditResult) || !Objects.equals(ClassAuditStatusEnum.UNAUDITED.getCode(), auditResult.getStatus()), "申请审核中，请勿重复提交");
        Long auditId = saveOrUpdateByClassIdAndStudentId(dto.getClassId(), dto.getStudentId(), dto.getStudentId(), dto.getAuditContent(), ClassAuditStatusEnum.UNAUDITED);
        //入课审核
        Spring.committed(() -> chatRemindSyncService.applyClass(classResult.getId(), classResult.getCourseName(), classResult.getName()));
        return auditId;
    }

    /**
     * 申请加课-免审核和手动审核的逻辑
     * 免审核入课程，不需要
     *
     * @param dto       加课dto
     * @param auditJson 审核数据
     * @return ClassJoinAuditResultDTO 返回关系用户加班成功的信息
     */
    @Transactional(rollbackFor = Exception.class)
    public ClassJoinAuditResultDTO autoAuditBoth(ClassJoinAuditCreateDTO dto, ClassAuditJsonParamDTO auditJson, Long studentId) {
        ClassResultDTO classResult = Optional.ofNullable(classService.findByClassId(dto.getClassId())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException(MessageUtils.message("remind.content.class.not.blank")));
        Long auditId;
        //将关系用户加入到班级中
        auditId = this.autoAuditRelationalIntoClass(classResult.getCourseId(), classResult.getId(), dto.getStudentId(), dto.getAuditContent(), YesNoEnum.YES.ordinal(), studentId, auditJson);
        //将虚拟用户加入到班级中
        auditJson.setRelationship(ClassStudentRelationshipEnum.虚拟主学生.getDescribe());
        classStudentService.insertStudent(dto.getStudentId(), studentId, classResult.getCourseId(), classResult.getId(), YesNoEnum.NO.ordinal(), 0L, auditJson);
        Spring.committed(() -> {
            //虚拟用户加课后处理
            classMqService.studentJoinClass(dto.getClassId(), studentId);
            //关系用户加入班级群
            remoteChatClient.classJoinGroup(dto.getClassId(), dto.getStudentId());
            //免审核入课只需要给老师发消息，不需要给关系用户发消息
            chatRemindSyncService.studentJoinClass(classResult.getId(), null, ChatRemindTypeEnum.AUTO_AUDIT);
        });

        return classJoinAuditConvert.convert(getById(auditId));
    }

    /**
     * 自动审核加入班级
     *
     * @param courseId     课程id
     * @param classId      班级id
     * @param studentId    学生id
     * @param auditContent 审核内容
     * @param auditJson    加班申请内容（审核内容转过来的字段）
     * @return Long
     */
    @Transactional(rollbackFor = Exception.class)
    public Long autoAuditRelationalIntoClass(Long courseId, Long classId, Long studentId, String auditContent, Integer isRelationalStudent, Long patStuRefId, ClassAuditJsonParamDTO auditJson) {
        classStudentService.insertStudent(studentId, studentId, courseId, classId, isRelationalStudent, patStuRefId, auditJson);
        //保存或更新审核数据
        Long auditId = this.saveOrUpdateByClassIdAndStudentId(classId, studentId, studentId, auditContent, ClassAuditStatusEnum.PASS);
        //添加加课记录
        classOperationLogService.insertStudentOperateLog(courseId, classId, studentId, auditId, ClassOperationLogTypeEnum.AUDIT_JOIN);
        return auditId;
    }

    /**
     * 判断学生是否有账号
     *
     * @param mobile      手机号
     * @param studentName 昵称
     * @return true-有账号，false-无账号
     */
    private UserResultDTO checkImitateUserAccount(String mobile, String studentName) {
        return R.as(userClient.findImitateByMobileAndNickname(mobile, studentName));
    }

    /**
     * 判断关系/虚拟用户是否在班级中
     *
     * @param classId           班级id
     * @param relationStudentId 用关系户id（通常为登录人）
     * @return true-在班级中，false-不在班级中
     */
    private Boolean checkUserIsInClass(Long classId, Long relationStudentId) {
        ClassStudentEntity classStudentEntity = classStudentService.selectByClassIdAndStudentId(classId, relationStudentId);
        return !Objects.isNull(classStudentEntity);
    }

    /**
     * 创建虚拟用户
     *
     * @param mobile      手机号
     * @param studentName 学生姓名
     * @return UserResultDTO
     */
    private UserResultDTO imitateUser(String mobile, String studentName) {
        UserImitateDTO userImitateDTO = new UserImitateDTO();
        userImitateDTO.setMobile(mobile);
        userImitateDTO.setNickName(studentName);
        return R.as(userClient.imitateUser(userImitateDTO));
    }

    /**
     * 老师拒绝学生加入班级
     *
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean reject(Long auditId) {
        ClassJoinAuditEntity entity = Optional.ofNullable(getById(auditId)).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("要审核的数据不存在"));
        ClassResultDTO classResult = Optional.ofNullable(classService.findByClassId(entity.getClassId())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException(MessageUtils.message("remind.content.class.not.blank")));
        saveOrUpdateByClassIdAndStudentId(entity.getClassId(), entity.getStudentId(), LoginHelper.getUserId(), entity.getAuditContent(), ClassAuditStatusEnum.REJECT);
        Spring.committed(() -> chatRemindSyncService.teacherReject(entity.getClassId(), entity.getStudentId(), classResult.getCourseName(), classResult.getName()));
        return true;
    }

    /**
     * 获取最新的一条审核记录
     *
     * @param classId   班级id
     * @param studentId 学生id
     * @return ClassJoinAuditResultDTO
     */
    @Override
    public ClassJoinAuditResultDTO findByClassIdAndStudentId(Long classId, Long studentId) {
        ClassJoinAuditQueryDTO query = new ClassJoinAuditQueryDTO();
        query.setClassId(classId);
        query.setStudentId(studentId);
        return classJoinAuditConvert.convert(getOne(wrapper(query)));
    }

    @Override
    public List<ClassJoinAuditResultDTO> findByClassIdAndStudentIdList(Long classId, List<Long> studentIdList) {
        LambdaQueryWrapper<ClassJoinAuditEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassJoinAuditEntity::getClassId, classId);
        wrapper.in(ClassJoinAuditEntity::getStudentId, studentIdList);
        return list(wrapper).stream().map(classJoinAuditConvert::convert).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchAccept(ListDataDTO<Long> dto) {
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(dto.getDataList()), "批量审核通过选中的内容不能为空");
        dto.getDataList().forEach(this::accept);
        return true;
    }

    @Override
    public Boolean batchAccept(List<ClassJoinAuditUpdateDTO> dto) {
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(dto), "批量审核通过选中的内容不能为空");
        dto.stream().map(ClassJoinAuditUpdateDTO::getId).collect(Collectors.toList()).forEach(this::accept);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchReject(ListDataDTO<Long> dto) {
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(dto.getDataList()), "批量拒绝选中的内容不能为空");
        dto.getDataList().forEach(this::reject);
        return true;
    }

    @Override
    public Boolean batchReject(List<ClassJoinAuditUpdateDTO> dto) {
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(dto), "批量拒绝选中的内容不能为空");
        dto.stream().map(ClassJoinAuditUpdateDTO::getId).collect(Collectors.toList()).forEach(this::reject);
        return true;
    }

    @Override
    public ClassJoinAuditResultDTO findLatestStatusByUserIdAndClassId(Long studentId, Long classId) {
        return baseMapper.findLatestStatusByUserIdAndClassId(studentId, classId);
    }

    @Override
    public Integer count(ClassJoinAuditQueryDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级id不能为空");
        CommonErrors.BAD_REQUEST.check(StringUtils.isNotBlank(dto.getStatus()), "审核状态不能为空");
        ClassResultDTO classResult = classService.findById(dto.getClassId());
        if (Objects.equals(ClassAuditEnum.AUTO.getCode(), classResult.getAuditMethod())) {
            return 0;
        }
        return baseMapper.findAuditCount(dto);
    }

    @Override
    public Long findNotAuditCountByClassId(Long classId) {
        ClassJoinAuditQueryDTO query = new ClassJoinAuditQueryDTO();
        query.setClassId(classId);
        query.setStatus(ClassAuditStatusEnum.UNAUDITED.getCode());
        return count(wrapper(query));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveOrUpdateByClassIdAndStudentId(Long classId, Long studentId, Long auditUserId, String auditContent, ClassAuditStatusEnum auditStatusEnum) {
        ClassJoinAuditResultDTO classJoinAuditResultDTO = findByClassIdAndStudentId(classId, studentId);
        if (Objects.isNull(classJoinAuditResultDTO)) {
            //添加审核记录
            ClassJoinAuditCreateDTO classJoinAudit = new ClassJoinAuditCreateDTO();
            classJoinAudit.setStudentId(studentId);
            classJoinAudit.setClassId(classId);
            classJoinAudit.setAuditUserId(auditUserId);
            classJoinAudit.setAuditTime(LocalDateTime.now());
            classJoinAudit.setStatus(auditStatusEnum.getCode());
            classJoinAudit.setAuditContent(classJoinAuditConvert.convertToArrayString(classJoinAuditConvert.convertToParam(auditContent)));
            return insert(classJoinAudit);
        } else {
            //更新审核数据
            ClassJoinAuditUpdateDTO classJoinAudit = classJoinAuditConvert.convertUpdate(classJoinAuditResultDTO);
            classJoinAudit.setAuditUserId(auditUserId);
            classJoinAudit.setAuditTime(LocalDateTime.now());
            classJoinAudit.setStatus(auditStatusEnum.getCode());
            classJoinAudit.setAuditContent(classJoinAuditConvert.convertToArrayString(classJoinAuditConvert.convertToParam(auditContent)));
            updateById(classJoinAudit);
            return classJoinAudit.getId();
        }
    }

    /**
     * 批量添加
     *
     * @param list
     * @return 返回审核结果
     * @Author dzy
     */
    @Override
    public boolean saveAllBatch(List<ClassJoinAuditEntity> list) {
        return this.saveBatch(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByClassIdAndStudentIdList(Long classId, List<Long> studentIdList) {
        List<ClassJoinAuditResultDTO> classJoinAuditResultDTOList = findByClassIdAndStudentIdList(classId, studentIdList);
        if (CollectionUtils.isNotEmpty(classJoinAuditResultDTOList)) {
            removeByIds(classJoinAuditResultDTOList.stream().map(ClassJoinAuditResultDTO::getId).collect(Collectors.toList()));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassJoinAuditResultDTO applyByPhone(ClassJoinAuditApplyByPhoneDTO dto) {
        String code = RedisUtils.getCacheObject(CacheConstants.CAPTCHA_CODE_KEY + dto.getMobile());
        //手机验证码校验
        CommonErrors.BAD_REQUEST.check(Objects.equals(dto.getSmsCode(), code), "验证码不正确");
        UserResultDTO user = R.as(userClient.findByMobile(dto.getMobile()));
        //注册并登录
        if (Objects.isNull(user)) {
            //手机号注册
            UserRegisterDTO registerDto = new UserRegisterDTO();
            registerDto.setMobile(dto.getMobile());
            registerDto.setSmsCode(dto.getSmsCode());
            //昵称
            registerDto.setNickName("新奇" + dto.getMobile());
            registerDto.setPassword(dto.getPassword());
            registerDto.setSchoolName("未知");
            registerDto.setUserRole(dto.getUserRole());
            user = R.as(userClient.register(registerDto));
            CommonErrors.BAD_REQUEST.check(Objects.nonNull(user), MessageUtils.message("注册失败"));

            // 同步示范课程
            if (Objects.equals(RegisterRoleEnum.TEACHER.getCode(), dto.getUserRole())) {
                demonstrateService.initAllCourse(user.getId());
            }

            UserResultDTO finalUser = user;
            CompletableFuture.runAsync(() -> remindContentClient.insert(new ChatRemindContentCreateDTO(finalUser.getId(), ChatRemindTypeEnum.FIRST_ENTRY, ChatRemindConstants.REMIND_FIRST_ENTRY_TEMPLATE)));
        }

        //申请加课
        ClassJoinAuditCreateDTO classJoinAuditCreateDTO = new ClassJoinAuditCreateDTO();
        classJoinAuditCreateDTO.setClassId(dto.getClassId());
        classJoinAuditCreateDTO.setAuditContent(dto.getAuditContent());
        classJoinAuditCreateDTO.setStudentId(user.getId());
        return this.apply(classJoinAuditCreateDTO);
    }
}
